<?php

namespace App\Models\Customer;

use App\Models\Concerns\ScopeFilterable;
use App\Models\Panx\Category;
use App\Models\Panx\Product;
use App\Models\Panx\ProductTag;
use App\Models\Store\Pack;
use App\Observers\BosCleanObserver;
use App\Services\Utils\Bosable;
use App\Services\Utils\Uuid;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\DB;

/**
 * @property int id
 * @property int category_id
 * @property int customer_id
 * @property int store_id
 * @property int version
 * @property string code
 * @property Product|null firstProduct - 单妆素材关联的第一个商品
 * @property Product|null|Collection pivotProducts - 整体妆容中素材关联的商品
 * @property-write Product|null|Collection pivot_products - 整体妆容中素材关联的商品
 * @property Product|null|Collection has_many_products - 单妆素材关联的商品
 * @property Product[]|Collection products
 * @property Pack[]|Collection packs
 * @property-write Product product
 * @property-read Product[]|Collection assetPivotProducts
 * @property string model_xml
 * @property-write string model_glass_android
 * @property-write string model_glass_ios
 * @property-write string xml_key - model xml 原始字段
 *
 * @method static self filterStoreAndCustomer(int $store_id, int $customer_id) - 过滤客户下的店铺的素材
 * @method static self filterCustomerNoStore(int $customer_id) - 过滤只属于客户 不属于店铺的素材
 * @method static self filterCategory(?int $category_id) - 按商品分类过滤
 * @mixin Builder
 */
class Asset extends Model
{
    use Bosable, ScopeFilterable;

    const NO_STORE_ID = 0;

    protected $bos_key_prefix = 'product/assets/';
    protected $bos_key_prefix_glass = 'product/assets/glass/{*}/';
    protected $bos_key_prefix_glass_android = 'product/assets/glass/Android/';
    protected $bos_key_prefix_glass_ios = 'product/assets/glass/IOS/';

    protected $table = 'assets';

    protected $guarded = [];

    public $bos_columns = ['model_xml'];

    protected $casts = [
        'customer_id' => 'int',
        'store_id'    => 'int',
        'category_id' => 'int',
        'version'     => 'int',
        'src_asset_id'=> 'int',
    ];

    /**
     * @param UploadedFile|string|null $model_glass_android
     * @param UploadedFile|string|null $model_glass_ios
     *
     * @return string
     * @throws \Exception
     */
    public function uploadGlassAsset($model_glass_android,
                                     $model_glass_ios)
    {
        // 这里如果只更新一个模型，需要保证两个模型文件名是一致的
        if (is_string($model_glass_android)) {
            $file_name = last(explode('/', $model_glass_android));
        } elseif (is_string($model_glass_ios)) {
            $file_name = last(explode('/', $model_glass_ios));
        } else {
            $file_name = Uuid::generate() . '.' . ($model_glass_android->guessClientExtension() ?: 'panxbundle');
        }

        if (is_file($model_glass_android)) {
            $this->uploadPostFileWithName($model_glass_android, $this->bos_key_prefix_glass_android, $file_name);
        }

        if (is_file($model_glass_ios)) {
            $this->uploadPostFileWithName($model_glass_ios, $this->bos_key_prefix_glass_ios, $file_name);
        }

        return $this->bos_key_prefix_glass . $file_name;
    }

    /**
     * @param $thumb_img
     * @throws \Exception
     */
    public function setThumbImgAttribute($thumb_img)
    {
        if (is_file($thumb_img)) {
            $this->attributes['thumb_img'] = $this->uploadPostFile($thumb_img, $this->bos_key_prefix);
        }
    }

    /**
     * @return mixed|null
     */
    public function getThumbImgAttribute()
    {
        if (!$this->attributes['thumb_img']) return null;

        return $this->getStaticUrl($this->attributes['thumb_img']);
    }

    /**
     * @param $texture_img
     * @throws \Exception
     */
    public function setTextureImgAttribute($texture_img)
    {
        if (is_file($texture_img)) {
            $this->attributes['texture_img'] = $this->uploadPostFile($texture_img, $this->bos_key_prefix);
        }
    }

    /**
     * @return mixed|null
     */
    public function getModelXmlAttribute()
    {
        if (!$this->attributes['model_xml']) return null;

        $url = $this->getStaticUrl($this->attributes['model_xml']);

        if ($this->isGlass()) {
            return urldecode($url); // recover {*}
        } else {
            return $url;
        }
    }

    /**
     * @param $model_xml
     * @throws \Exception
     */
    public function setModelXmlAttribute($model_xml)
    {
        if (is_file($model_xml)) {
            $this->attributes['model_xml'] = $this->uploadPostFile($model_xml, $this->bos_key_prefix);
        } elseif (is_string($model_xml)) {
            $this->attributes['model_xml'] = $model_xml;
        }
    }

    /**
     * @return mixed|null
     */
    public function getTextureImgAttribute()
    {
        if (!$this->attributes['texture_img']) return null;

        return $this->getStaticUrl($this->attributes['texture_img']);
    }

    /**
     * @return \Illuminate\Database\Eloquent\Relations\HasMany
     */
    public function products()
    {
        return $this->hasMany(Product::class, 'asset_id', 'id');
    }

    /**
     * @return \Illuminate\Database\Eloquent\Relations\HasOne
     */
    public function firstProduct()
    {
        return $this->hasOne(Product::class, 'asset_id', 'id')
            ->where('is_sale', Product::IS_SALE)
            ->where('is_deleted', Product::IS_NO_DELETE)
            ->latest('created_at');
    }

    /**
     * @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
     */
    public function packs()
    {
        return $this->belongsToMany(Pack::class, 'pack_pivot_asset', 'asset_id', 'pack_id');
    }

    /**
     * 注意使用这个方法找出来的 products 需要使用 Pivot 中的 pack_id 过滤出对应的整妆
     *
     * @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
     */
    public function assetPivotProducts()
    {
        return $this
            ->belongsToMany(
            Product::class, 'pack_asset_pivot_product',
            'asset_id', 'product_id'
            )
            ->withPivot('pack_id');
    }


    /**
     * @deprecated - 这个查询效率太低，已经不再使用了
     *
     * 查找整体妆容下的素材对应的产品
     *
     * @param Pack $pack
     *
     * @return Collection
     */
    public function getPivotProducts(Pack $pack): Collection
    {
        $product_ids = DB::table('pack_asset_pivot_product')->where([
            ['asset_id', $this->id],
            ['pack_id', $pack->id],
        ])->pluck('product_id');

        return (new Product)
            ->whereIn('id', $product_ids)
            ->get();
    }

    /**
     * 查找单品妆容下的素材对应的产品
     *
     * @return Collection
     */
    public function getPivotProductsForPackIds(): Collection
    {
        $products = $this->assetPivotProducts()
            ->with('thumbImage')
            ->get()
            ->unique('id');

        return $products;
    }

    /**
     * @param Builder $query
     * @param $customer_id
     * @param int $store_id
     * @return Builder
     */
    public function scopeFilterStoreAndCustomer(Builder $query, $store_id, $customer_id)
    {
        return $query->where('customer_id', $customer_id)
            ->whereIn('store_id', [$store_id, self::NO_STORE_ID]);
    }

    /**
     * @param Builder $query
     * @param $customer_id
     * @return Builder
     */
    public function scopeFilterCustomerNoStore(Builder $query, $customer_id)
    {
        return $query->where([
            'customer_id' => $customer_id,
            'store_id'    => self::NO_STORE_ID
        ]);
    }

    /**
     * @used-by filterCategory
     *
     * @param Builder $query
     * @param $category_id
     * @return Builder
     */
    public function scopeFilterCategory(Builder $query, ?int $category_id)
    {
        if (is_null($category_id)) return $query;

        return $query->where(['category_id' => $category_id,]);
    }

    /**
     * 注册删除 bosKey 事件绑定
     */
    protected static function boot()
    {
        parent::boot();

        /**
         * 监听bos清理事件
         *
         * @link https://coding.net/u/zeon/p/beauty-mirror/task/3803123 -  #656 模型组要求不清理
         */
//        self::observe(BosCleanObserver::class);
    }

    /**
     * @param UploadedFile $file
     * @param string $dir
     * @param bool $keep_name
     * @return string
     * @throws \Exception
     */
    public function uploadFileToUrl(UploadedFile $file, $dir, $keep_name = false)
    {
        $bos_key = $this->uploadPostFile($file, $dir, !$keep_name);

        $url = $this->getStaticUrl($bos_key);

        return $url;
    }

    /**
     *  从pack_asset_pivot_product表中查找指定pack_id的products
     *
     * @param $pack_id
     * @return Collection
     */
    public function packAssetPivotProducts(int $pack_id): Collection
    {
        return $this->assetPivotProducts
            ->filter(function(Product $product) use ($pack_id){
                // product with pack_asset_pivot_product pivot pack_id
                /** @noinspection PhpUndefinedFieldInspection */
                return $product->pivot->pack_id === $pack_id;
            })
            ->values();
    }

    public function isGlass(): bool
    {
        return $this->category_id === Category::GLASS_ID;
    }
}
